
import *as http from "http"
import *as crypto from "crypto"
import *as q from "querystring"

export interface id及密码 {
    id: string,
    秘钥: string
}
export interface 翻译设置 {
    有道设置: id及密码
    百度设置: id及密码
    原文代码?: "EN" | "zh_CHS" | "en" | "zh",
    目标代码?: "EN" | "zh_CHS" | "en" | "zh",
}
export enum 翻译主站 {
    百度 = "http://api.fanyi.baidu.com/api/trans/vip/translate?",
    有道 = "http://openapi.youdao.com/api?"
}
export enum 百度错误代码 {
    成功 = 52000,
    请求超时 = 52001,
    系统错误 = 52002,
    未授权用户 = 52003,
    必填参数为空 = 54000,
    签名错误 = 54001,
    访问频率受限 = 54003,
    账户余额不足 = 54004,
    请求太长 = 54005,
    客户端IP非法 = 58000,
    译文语言方向不支持 = 58001
}
export enum 有道错误代码 {
    成功 = 0,
    缺少必填的参数 = 101,
    不支持的语言类型 = 102,
    翻译文本过长 = 103,
    不支持的API类型 = 104,
    不支持的签名类型 = 105,
    不支持的响应类型 = 106,
    不支持的传输加密类型 = 107,
    应用ID = 108,
    编码格式不正确 = 109,
    无相关服务的有效实例 = 110,
    开发者账号无效 = 111,
    解密失败 = 201,
    签名检验失败 = 202,
    访问IP地址不在 = 203,
    辞典查询失败 = 301,
    翻译查询失败 = 302,
    服务端的其它异常 = 303,
    账户已经欠费停 = 401
}
const 错误元数据 = {
    0: "成功",
    101: "缺少必填的参数",
    102: "不支持的语言类型",
    103: "翻译文本过长",
    104: "不支持的API类型",
    105: "不支持的签名类型",
    106: "不支持的响应类型",
    107: "不支持的传输加密类型",
    108: "应用ID",
    109: "编码格式不正确",
    110: "无相关服务的有效实例",
    111: "开发者账号无效",
    201: "解密失败",
    202: "签名检验失败",
    203: "访问IP地址不在",
    301: "辞典查询失败",
    302: "翻译查询失败",
    303: "服务端的其它异常",
    401: "账户已经欠费停",
    52000: "成功",
    52001: "请求超时",
    52002: "系统错误",
    52003: "未授权用户",
    54000: "必填参数为空",
    54001: "签名错误",
    54003: "访问频率受限",
    54004: "账户余额不足",
    54005: "请求太长",
    58000: "客户端IP非法",
    58001: "译文语言方向不支持"
}
export type 百度结果 = {
    from: string,
    to: string,
    trans_result: 百度译文[]
}
export type 百度译文 = {
    src: string,
    dst: string
}
export type 错误结果 = {
    error_code: 百度错误代码 | 有道错误代码,
    error_msg: string
}

export type 有道结果 = {
    query: string,
    translation: string[],
    errorCode: 有道错误代码,
    basic?: { explains: 有道词典结果[] },
    l: "EN2zh-CHS" | "zh-CHS2EN"
}
export type 有道词典结果 = {
    词性: string
    结果: string[]
}

export type 翻译结果 = 有道结果 | 百度结果 | 错误结果

export function 是有道结果(结果: 翻译结果): 结果 is 有道结果 {
    if (Object.prototype.hasOwnProperty.call(结果, 'errorCode')) {
        return true
    }
}
export function 是有道词典结果(结果: 翻译结果): 结果 is 有道结果 {
    if (Object.prototype.hasOwnProperty.call(结果, 'basic')) {
        return true
    }
}
export function 是百度结果(结果: 翻译结果): 结果 is 百度结果 {
    if (Object.prototype.hasOwnProperty.call(结果, 'trans_result')) {
        return true
    }
}
export function 是百度错误(结果: 翻译结果): 结果 is 错误结果 {
    if (Object.prototype.hasOwnProperty.call(结果, 'error_code')) {
        return true
    }
}
export function 全角转半角(文本: string) {
    var 结果 = "";
    for (var i = 0; i < 文本.length; i++) {
        if (文本.charCodeAt(i) >= 65281 && 文本.charCodeAt(i) <= 65374) {
            结果 += String.fromCharCode(文本.charCodeAt(i) - 65248)
        } else if (文本.charCodeAt(i) == 12288) {
            结果 += ' ';
        } else {
            结果 += 文本[i];
        }
    }
    return 结果
}
export function 翻译(内容: string | string[], 选项: 翻译设置, 回调: (结果: 翻译结果) => void) {

    function 确保为有道语言代码(语言代码: string): "EN" | "zh_CHS" | "en" | "zh" {
        switch (语言代码) {
            case "auto":
            case "en":
                return "EN"
            case "zh":
                return "zh_CHS"
            default:
                return 语言代码 as "EN" | "zh_CHS" | "en" | "zh"
        }
    }

    function 确保为百度语言代码(语言代码: string): "EN" | "zh_CHS" | "en" | "zh" {
        switch (语言代码) {
            case "EN":
                return "en"
            case "zh_CHS":
                return "zh"
            default:
                return 语言代码 as "EN" | "zh_CHS" | "en" | "zh"
        }
    }
    function 生成参数(主站: 翻译主站) {
        let 地址: string
        let id: string
        let 密码: string
        let 链接: string
        let 组合秘钥: string
        let md5: crypto.Hash
        let 原文 = 选项.原文代码 || "EN";
        let 目标 = 选项.目标代码 || "zh_CHS";
        let 时间戳 = (new Date).getTime();
        if (主站 === 翻译主站.有道 && 选项.有道设置) {
            地址 = 翻译主站.有道
            id = 选项.有道设置.id
            密码 = 选项.有道设置.秘钥
            原文 = 确保为有道语言代码(原文)
            目标 = 确保为有道语言代码(目标)
            内容 = (typeof 内容 !== "string" ? 内容.join(" ") : 内容).trim()
            组合秘钥 = id + 内容 + 时间戳 + 密码;
            md5 = crypto.createHash("md5").update(组合秘钥)
            链接 = `${地址}q=${q.escape(内容)}&from=${原文}&to=${目标}&appKey=${id}&salt=${时间戳}&sign=${md5.digest('hex')}`
        } else if (选项.百度设置) {
            地址 = 翻译主站.百度
            id = 选项.百度设置.id
            密码 = 选项.百度设置.秘钥
            原文 = 确保为百度语言代码(原文)
            目标 = 确保为百度语言代码(目标)
            组合秘钥 = id + 内容 + 时间戳 + 密码;
            md5 = crypto.createHash("md5").update(组合秘钥)
            内容 = (typeof 内容 !== "string" ? 内容.join("\n") : 内容).trim()
            链接 = `${地址}q=${q.escape(内容)}&from=${原文}&to=${目标}&appid=${id}&salt=${时间戳}&sign=${md5.digest('hex')}`
        }
        return 链接
    }

    执行(生成参数(翻译主站.有道))

    function 执行(链接: string) {
        if (!链接) {
            回调({ error_code: 有道错误代码.缺少必填的参数, error_msg: 错误元数据[有道错误代码.缺少必填的参数] })
            return
        }
        let rsq = http.get(链接, res => {
            let 数据 = ""
            res.on("data", d => {
                数据 += d
            })
            res.on("end", () => {
                let 结果 = JSON.parse(数据)
                if (是百度错误(结果)) {
                    回调({ error_code: 结果.error_code, error_msg: 错误元数据[结果.error_code] })
                    return
                }
                if (是有道结果(结果)) {
                    if ((+结果.errorCode) !== 有道错误代码.成功) {
                        执行(生成参数(翻译主站.百度))
                        return
                    }
                    delete 结果["dict"]
                    delete 结果["web"]
                    delete 结果["webdict"]
                    let 词典结果 = 结果.basic
                    let 数组: 有道词典结果[]
                    if (词典结果 && 词典结果.explains) {
                        let 处理内容 = 词典结果.explains as any[]
                        for (let 内容组 of 处理内容) {
                            内容组 = 全角转半角(内容组).replace(/;/g, ",").replace(/ /g, "")
                            let 词性字符 = 内容组 && 内容组.substr(0, 内容组.indexOf("."))
                            let 内容 = (内容组.substr(内容组.indexOf(".") + 1)).split(',');
                            (数组 || (数组 = [])).push({ 词性: 词性字符, 结果: 内容 })
                        }
                    }
                    if (词典结果 && 词典结果.explains && 数组) {
                        delete 结果.basic['us-phonetic']
                        delete 结果.basic['uk-phonetic']
                        delete 结果.basic['phonetic']
                        结果.basic.explains = 数组
                    }
                }
                回调(结果)
                return
            })
        })
        rsq.end()
    }

}
/*
// 使用 
(function 翻译词组() {
    const 选项: 翻译.翻译设置 = {
        有道设置: {
            id: "78781d9495793f1d",
            秘钥: "jQJeK5dWB2n2lbc9vkYrNjztUUhLlUie",
        },
        百度设置: {
            id: "20170410000044514",
            秘钥: "GbDh50rb08QIYaSNMd4J"
        },
        原文代码: "EN",
        目标代码: "zh_CHS"
    }

    翻译.翻译("yellow", 选项, (数据) => {
        if (翻译.是有道词典结果(数据)) {
            console.log("11: ", 数据.basic.explains)
        } if (翻译.是有道结果(数据)) {
            console.log("22: ", 数据.translation)
        } if (翻译.是百度结果(数据)) {
            console.log("33: ", 数据.trans_result)
        } if (翻译.是百度错误(数据)) {
            console.log("44: ", 数据)
        }
    })

})()
*/
